package com.stock.calculator.helper;

import java.io.IOException;
import java.io.StringReader;
import java.util.Calendar;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import com.stock.calculator.utils.URLHttpConnect;

public class StockHelper {

    private final String      KEY_RATIO_10_YR_SYMMARY_URL;
    private final String      FINANCIAL_10_YR_SUMMARY_URL;
    private final String      DIVIDEND_SUMMARY_URL;
    private final String      FINANCIAL_RESULTS_URL;
    private final String      EARNINGS_ESTIMATES_URL;

    private static String[][] tenYrSummaryTable;
    private static String[][] financialResultTable;
    private static String[][] earningsEstimatesTable;
    private static String[][] earningsGrowthRatesTable;

    public StockHelper(String tickerSymbol) {
        Calendar nowCalendar = Calendar.getInstance();
        int twenteyYrBefore = nowCalendar.get(Calendar.YEAR) - 21;

        KEY_RATIO_10_YR_SYMMARY_URL = "http://investing.money.msn.com/investments/key-ratios?page=TenYearSummary&symbol="
                + tickerSymbol;
        FINANCIAL_10_YR_SUMMARY_URL = "http://investing.money.msn.com/investments/financial-statements?symbol="
                + tickerSymbol;
        DIVIDEND_SUMMARY_URL = String.format(
                "http://ichart.finance.yahoo.com/table.csv?s=%s&a=00&b=0&c=%d&d=%02d&e=%d&f=%d&g=v&ignore=.csv",
                tickerSymbol, twenteyYrBefore, nowCalendar.get(Calendar.MONTH), nowCalendar.get(Calendar.DAY_OF_MONTH),
                nowCalendar.get(Calendar.YEAR));
        FINANCIAL_RESULTS_URL = "http://investing.money.msn.com/investments/financial-results/?symbol=" + tickerSymbol;
        EARNINGS_ESTIMATES_URL = "http://investing.money.msn.com/investments/earnings-estimates?symbol=" + tickerSymbol;

        System.out.println(DIVIDEND_SUMMARY_URL);
    }

    public String[] fetch10YrBookValueTable() throws IOException {
        String[][] tenYrSummaryTable = fetch10YrSummaryTable();

        String[] tenYrBookValueTable = new String[tenYrSummaryTable.length - 1];

        for (int i = 0; i < tenYrBookValueTable.length; ++i) {
            tenYrBookValueTable[i] = tenYrSummaryTable[i + 1][5];
        }

        return tenYrBookValueTable;
    }

    public String fetchEarningsPerShare() throws IOException {
        String[][] financialResultTable = fetchFinancialResultTable();

        return financialResultTable[6][1];
    }

    public String fetchCurrentBookValue() throws IOException {
        String[][] financialResultTable = fetchFinancialResultTable();

        return financialResultTable[7][1];
    }

    public String fetchDividendYield() throws IOException {
        String[][] financialResultTable = fetchFinancialResultTable();

        return financialResultTable[8][1];
    }

    public String fetch5YrEarningsGrowthRate() throws IOException {
        String[][] earningsGrowthRatesTable = fetchEarningsGrowthRatesTable();

        return earningsGrowthRatesTable[1][4];
    }

    public String[][] fetchFinancialResultTable() throws IOException {
        if (financialResultTable != null)
            return financialResultTable;

        String response = URLHttpConnect.httpGet(FINANCIAL_RESULTS_URL);

        Document doc = null;
        try {
            doc = buildDOM(response);
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        }

        Node nodes1 = doc.getFirstChild().getFirstChild();
        Node nodes2 = nodes1.getNextSibling();
        Node nodes3 = nodes2.getNextSibling();
        // Node nodes4 = nodes3.getNextSibling();
        // Node nodes5 = nodes4.getNextSibling();
        // Node nodes6 = nodes5.getNextSibling();
        // Node nodes7 = nodes6.getNextSibling();

        Node nodes1_body = nodes1.getFirstChild().getNextSibling().getNextSibling();
        Node nodes2_body = nodes2.getFirstChild().getNextSibling().getNextSibling();
        Node nodes3_body = nodes3.getFirstChild().getNextSibling();

        NodeList nodes1_body_list = nodes1_body.getChildNodes();
        NodeList nodes2_body_list = nodes2_body.getChildNodes();
        NodeList nodes3_body_list = nodes3_body.getChildNodes();

        int nodes1_length = nodes1_body_list.getLength();
        int nodes2_length = nodes2_body_list.getLength();
        int nodes3_length = nodes3_body_list.getLength();

        financialResultTable = new String[nodes1_length + nodes2_length + nodes3_length][2];

        putBody(financialResultTable, nodes1_length, nodes1_body_list, 0);
        putBody(financialResultTable, nodes2_length, nodes2_body_list, nodes1_length);
        putBody(financialResultTable, nodes3_length, nodes3_body_list, nodes1_length + nodes2_length);

        return financialResultTable;
    }

    private void putBody(String result[][], int node_length, NodeList node_list, int offset) {

        for (int i = 0; i < node_length; ++i) {
            Node nodeDataName = node_list.item(i).getFirstChild().getFirstChild().getFirstChild();
            Node nodeDataValue = node_list.item(i).getFirstChild().getNextSibling().getFirstChild().getFirstChild();

            result[offset + i][0] = nodeDataName.getNodeValue();
            result[offset + i][1] = nodeDataValue.getNodeValue();
        }

    }

    private Document buildDOM(String response) throws IOException, SAXException, ParserConfigurationException {
        String[] lines = response.split("\n");

        StringBuilder xml = new StringBuilder("<html>");
        boolean include = false;

        for (String line : lines) {
            boolean line_contains = false;

            if (line.contains("<table") || line.contains("table>")) {
                line_contains = true;
                include = !include;
            }

            if (include || line_contains)
                if (!line.trim().isEmpty())
                    xml.append(line.trim().replace("&", "&amp;"));
        }
        xml.append("</html>");

        System.out.println(xml);

        Document doc = null;
        doc = DocumentBuilderFactory.newInstance().newDocumentBuilder()
                .parse(new InputSource(new StringReader(xml.toString())));
        doc.getDocumentElement().normalize();

        return doc;
    }

    public void fetchDividendPaidTable() throws IOException {

        String response = URLHttpConnect.httpGet(DIVIDEND_SUMMARY_URL);

        System.out.println(response);
    }

    void print(Node... nodes) {
        for (Node node : nodes)
            System.out.print(node + " ");
        System.out.println();
    }

    void print(NodeList... nodeLists) {
        for (NodeList nodeList : nodeLists) {
            System.out.print(nodeList.item(0).getFirstChild().getFirstChild().getFirstChild());
        }
        System.out.println();
        for (NodeList nodeList : nodeLists) {
            System.out.print(nodeList.getLength() + " ");
        }
        System.out.println();
    }

    public String[][] fetchEarningsEstimateTable() throws IOException {
        fetchEarningsEstimates();
        return earningsEstimatesTable;
    }

    public String[][] fetchEarningsGrowthRatesTable() throws IOException {
        fetchEarningsEstimates();
        return earningsGrowthRatesTable;
    }

    private void fetchEarningsEstimates() throws IOException {
        if (earningsEstimatesTable != null && earningsGrowthRatesTable != null)
            return;

        String response = URLHttpConnect.httpGet(EARNINGS_ESTIMATES_URL);

        Document doc = null;
        try {
            doc = buildDOM(response);
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        }
        Node nodes1 = doc.getFirstChild().getFirstChild();
        Node nodes2 = nodes1.getNextSibling();
        Node nodes3 = nodes2.getNextSibling();
        Node nodes4 = nodes3.getNextSibling();
        Node nodes5 = nodes4.getNextSibling();
        Node nodes6 = nodes5.getNextSibling();

        Node nodes1_headder = nodes1.getFirstChild().getNextSibling();
        Node nodes2_headder = nodes2.getFirstChild().getNextSibling();
        Node nodes3_headder = nodes3.getFirstChild().getNextSibling();
        Node nodes4_headder = nodes4.getFirstChild().getNextSibling();
        Node nodes5_headder = nodes5.getFirstChild();
        Node nodes6_headder = nodes6.getFirstChild();
        Node nodes1_body = nodes1_headder.getNextSibling();
        Node nodes2_body = nodes2_headder.getNextSibling();
        Node nodes3_body = nodes3_headder.getNextSibling();
        Node nodes4_body = nodes4_headder.getNextSibling();
        Node nodes5_body = nodes5_headder.getNextSibling();
        Node nodes6_body = nodes6_headder.getNextSibling();

        NodeList nodes1_headder_list = nodes1_headder.getFirstChild().getChildNodes();
        NodeList nodes2_headder_list = nodes2_headder.getFirstChild().getChildNodes();
        NodeList nodes3_headder_list = nodes3_headder.getFirstChild().getChildNodes();
        NodeList nodes4_headder_list = nodes4_headder.getFirstChild().getChildNodes();
        NodeList nodes1_body_list = nodes1_body.getChildNodes();
        NodeList nodes2_body_list = nodes2_body.getChildNodes();
        NodeList nodes3_body_list = nodes3_body.getChildNodes();
        NodeList nodes4_body_list = nodes4_body.getChildNodes();

        int nodes1_length = nodes1_headder_list.getLength();
        int nodes2_length = nodes2_headder_list.getLength();
        int nodes3_length = nodes3_headder_list.getLength();
        int nodes4_length = nodes4_headder_list.getLength();

        earningsEstimatesTable = new String[nodes1_body_list.getLength() + 1][];
        earningsGrowthRatesTable = new String[nodes4_body_list.getLength() + 1][];

        // Putting headders
        earningsEstimatesTable[0] = new String[nodes1_length];
        earningsGrowthRatesTable[0] = new String[nodes4_length];

        putHeadder(earningsEstimatesTable, false, nodes1_length, nodes1_headder_list, 0);
        putHeadder(earningsGrowthRatesTable, false, nodes4_length, nodes4_headder_list, 0);

        // Putting body
        for (int i = 0; i < earningsEstimatesTable.length - 1; i++) {
            earningsEstimatesTable[i + 1] = new String[nodes1_length];
            putBody(earningsEstimatesTable, false, nodes1_length, nodes1_body_list, i, 0);
        }

        for (int i = 0; i < earningsGrowthRatesTable.length - 1; i++) {
            earningsGrowthRatesTable[i + 1] = new String[nodes4_length];
            putBody(earningsGrowthRatesTable, false, nodes4_length, nodes4_body_list, i, 0);
        }

    }

    public String[][] fetch10YrSummaryTable() throws IOException {
        if (tenYrSummaryTable != null)
            return tenYrSummaryTable;

        String response = URLHttpConnect.httpGet(KEY_RATIO_10_YR_SYMMARY_URL);
        String response2 = URLHttpConnect.httpGet(FINANCIAL_10_YR_SUMMARY_URL);

        Document doc = null;
        try {
            doc = buildDOM(response + response2);
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        }

        Node nodes1 = doc.getFirstChild().getFirstChild();
        Node nodes2 = nodes1.getNextSibling();
        Node nodes3 = nodes2.getNextSibling();
        Node nodes4 = nodes3.getNextSibling();

        print(nodes1, nodes2, nodes3, nodes4);

        Node nodes1_headder = nodes1.getFirstChild();
        Node nodes2_headder = nodes2.getFirstChild();
        Node nodes3_headder = nodes3.getFirstChild().getNextSibling();
        Node nodes4_headder = nodes4.getFirstChild().getNextSibling();
        Node nodes1_body = nodes1_headder.getNextSibling();
        Node nodes2_body = nodes2_headder.getNextSibling();
        Node nodes3_body = nodes3_headder.getNextSibling();
        Node nodes4_body = nodes4_headder.getNextSibling();

        NodeList nodes1_headder_list = nodes1_headder.getFirstChild().getChildNodes();
        NodeList nodes2_headder_list = nodes2_headder.getFirstChild().getChildNodes();
        NodeList nodes3_headder_list = nodes3_headder.getFirstChild().getChildNodes();
        NodeList nodes4_headder_list = nodes4_headder.getFirstChild().getChildNodes();
        NodeList nodes1_body_list = nodes1_body.getChildNodes();
        NodeList nodes2_body_list = nodes2_body.getChildNodes();
        NodeList nodes3_body_list = nodes3_body.getChildNodes();
        NodeList nodes4_body_list = nodes4_body.getChildNodes();

        int nodes1_length = nodes1_headder_list.getLength();
        int nodes2_length = nodes2_headder_list.getLength();
        int nodes3_length = nodes3_headder_list.getLength();
        int nodes4_length = nodes4_headder_list.getLength();

        tenYrSummaryTable = new String[nodes1_body_list.getLength() + 1][]; // One
                                                                            // for
                                                                            // the
        // headder

        int result_length = nodes1_length + nodes2_length + nodes3_length + nodes4_length - 3;

        // Putting headders
        tenYrSummaryTable[0] = new String[result_length];

        putHeadder(tenYrSummaryTable, false, nodes1_length, nodes1_headder_list, 0);
        putHeadder(tenYrSummaryTable, true, nodes2_length, nodes2_headder_list, nodes1_length - 1);
        putHeadder(tenYrSummaryTable, true, nodes3_length, nodes3_headder_list, nodes1_length + nodes2_length - 2);
        putHeadder(tenYrSummaryTable, true, nodes4_length, nodes4_headder_list, nodes1_length + nodes2_length
                + nodes3_length - 3);

        // Putting body
        for (int i = 0; i < tenYrSummaryTable.length - 1; i++) {
            tenYrSummaryTable[i + 1] = new String[result_length];

            putBody(tenYrSummaryTable, false, nodes1_length, nodes1_body_list, i, 0);
            putBody(tenYrSummaryTable, true, nodes2_length, nodes2_body_list, i, nodes1_length - 1);
            putBody(tenYrSummaryTable, true, nodes3_length, nodes3_body_list, i, nodes1_length + nodes2_length - 2);
            putBody(tenYrSummaryTable, true, nodes4_length, nodes4_body_list, i, nodes1_length + nodes2_length
                    + nodes3_length - 3);
        }

        return tenYrSummaryTable;
    }

    private void putHeadder(String result[][], boolean skipFirst, int node_length, NodeList node_list, int offset) {
        for (int i = skipFirst ? 1 : 0; i < node_length; ++i) {
            Node node_data = node_list.item(i).getFirstChild().getFirstChild();

            String value = "";
            while (node_data != null) {
                if (node_data.getNodeValue() != null)
                    value += " " + node_data.getNodeValue();

                node_data = node_data.getNextSibling();
            }

            result[0][offset + i] = value;
        }
    }

    private void putBody(String result[][], boolean skipFirst, int node_length, NodeList node_list, int i, int offset) {

        for (int j = skipFirst ? 1 : 0; j < node_length; ++j) {
            Node node_data = node_list.item(i).getChildNodes().item(j).getFirstChild().getFirstChild();
            String node_value = null;
            if (node_data == null)
                node_value = null;
            else if (node_data.getNodeValue() != null) {
                node_value = node_data.getNodeValue();
            } else
                node_value = node_data.getFirstChild().getNodeValue();

            result[i + 1][offset + j] = node_value;
        }

    }

    public static void main(String... s) throws IOException {

        new StockHelper("FLXS").fetchDividendPaidTable();

        // String[][] result = new StockHelper("ORCL").fetch10YrSummaryTable();
        //
        // if (result != null) {
        // for (String[] rows : result) {
        // for (String string : rows)
        // System.out.format("%23s", string);
        // System.out.println();
        // }
        // }
    }
}
